package com.cwd.arm.application.service.read;

import com.cwd.arm.application.dto.MonthAmountTotalDto;
import com.cwd.arm.application.dto.board.*;
import com.cwd.arm.application.service.read.facade.BoardReadService;
import com.cwd.arm.application.service.read.facade.MonthAmountTotalReadService;
import com.cwd.arm.common.util.AviatorEvaluatorUtil;
import com.cwd.arm.common.util.BigDecimalUtil;
import com.cwd.arm.common.util.DateUtil;
import com.cwd.arm.infrastructure.dao.ProjectDao;
import com.cwd.arm.infrastructure.po.ProjectPo;
import com.cwd.arm.infrastructure.query.ProjectDaoQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created by yan on 22-2-17.
 */
@Repository
@Primary
public class BoardReadServiceImpl implements BoardReadService {

    @Autowired
    private ProjectDao projectDao;

    @Autowired
    private MonthAmountTotalReadService monthAmountTotalReadService;

    @Override
    public RtDto getRt() {
        RtDto rtDto = new RtDto();
        BigDecimal confirmAmount = projectDao.getTotalConfirmAmount();
        rtDto.setConfirmAmount(confirmAmount);
        BigDecimal receivedAmount = projectDao.getTotalReceivedAmount();
        rtDto.setReceivedAmount(receivedAmount);
        rtDto.setReceivableAmount(BigDecimalUtil.sub(confirmAmount,receivedAmount));
        BigDecimal payAmount = projectDao.getTotalPayAmount();
        rtDto.setPayAmount(payAmount);
        BigDecimal contractAmount = projectDao.getTotalContractAmount();
        BigDecimal grossRate = AviatorEvaluatorUtil.grossRate(payAmount,contractAmount);
        rtDto.setGrossRate(grossRate);
        rtDto.setGrossRateWarn(AviatorEvaluatorUtil.grossRateWarn(grossRate));
        return rtDto;
    }

    @Override
    public List<MonthAmountDto> getMonthCashAmount(Integer year) {
        List<MonthAmountTotalDto> monthAmountTotalDtoList = monthAmountTotalReadService.selectByYear(year);
        List<MonthAmountDto> monthAmountDtoList = monthAmountTotalDtoList.stream().map(dto->convertToMonthAmountDto(dto)).collect(Collectors.toList());
        return monthAmountDtoList;
    }

    @Override
    public List<MonthRateDto> getMonthReceivableRate(Integer year) {
        List<MonthAmountTotalDto> monthAmountTotalDtoList = monthAmountTotalReadService.selectByYear(year);
        List<MonthRateDto> dtoList = monthAmountTotalDtoList.stream().map(dto->convertToMonthRateDto(dto)).collect(Collectors.toList());
        return dtoList;
    }

    @Override
    public List<QAmountDto> getQMonthConfirmAmount(Integer year) {
        List<MonthAmountTotalDto> monthAmountTotalDtoList = monthAmountTotalReadService.selectByYear(year);
        Map<Integer,List<MonthAmountTotalDto>> map = monthAmountTotalDtoList.stream().collect(Collectors.groupingBy(totalDto -> DateUtil.getQ(totalDto.getFyMonth())));
        List<QAmountDto> dtoList= map.entrySet().stream().map(et ->convertToQAmountDto(et.getKey(),et.getValue())).collect(Collectors.toList());
        return dtoList;
    }

    @Override
    public List<YearAmountDto> getYearConfirmAmount() {
        return monthAmountTotalReadService.getYearConfirmAmount();
    }

    @Override
    public BigDecimal getReceivedRate() {
        BigDecimal totalReceivedAmount = projectDao.getTotalReceivedAmount();
        return BigDecimalUtil.div2(totalReceivedAmount,getTotalCloseAmount());
    }

    @Override
    public BigDecimal getConfirmRate() {
        BigDecimal totalConfirmAmount = projectDao.getTotalConfirmAmount();
        return BigDecimalUtil.div2(totalConfirmAmount,getTotalCloseAmount());
    }

    private BigDecimal getTotalCloseAmount() {
        List<ProjectPo> projectPoList = projectDao.getList(new ProjectDaoQuery());
        return projectPoList.stream().map(po->getCloseAmount(po)).reduce(BigDecimal.ZERO,BigDecimal::add);
    }

    private BigDecimal getCloseAmount(ProjectPo projectPo){
        if(BigDecimalUtil.hasRecord(projectPo.getCloseAmount())){
            return projectPo.getCloseAmount();
        }
        return projectPo.getContractAmount();
    }

    private MonthAmountDto convertToMonthAmountDto(MonthAmountTotalDto totalDto){
        MonthAmountDto monthAmountDto = new MonthAmountDto();
        monthAmountDto.setMonth(totalDto.getFyMonth());
        monthAmountDto.setAmount(BigDecimalUtil.sub(totalDto.getReceivedAmount(),totalDto.getActualPayAmount()));
        return monthAmountDto;
    }

    private MonthRateDto convertToMonthRateDto(MonthAmountTotalDto totalDto){
        MonthRateDto monthRateDto = new MonthRateDto();
        monthRateDto.setMonth(totalDto.getFyMonth());
        if(BigDecimalUtil.hasRecord(totalDto.getConfirmAmount())){
            monthRateDto.setRate(BigDecimalUtil.div2(totalDto.getReceivedAmount(),totalDto.getConfirmAmount()));
        }else{
            monthRateDto.setRate(BigDecimal.ONE);
        }
        return monthRateDto;
    }

    private QAmountDto convertToQAmountDto(Integer q,List<MonthAmountTotalDto> totalDtoList){
        QAmountDto qAmountDto = new QAmountDto();
        qAmountDto.setQ(q);
        BigDecimal qConfirmIncome = totalDtoList.stream().map(totalDto -> totalDto.getConfirmAmount()).reduce(BigDecimal.ZERO,BigDecimal::add);
        qAmountDto.setAmount(qConfirmIncome);
        return qAmountDto;
    }
}
